package org.dxy.domain.model.aggregate.impl;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.event.mbom.*;
import org.dxy.domain.event.substitute.*;
import org.dxy.domain.model.aggregate.MBOMAggRoot;
import org.dxy.domain.model.entity.SubstituteMaterial;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * MBOM聚合根实现
 * @author dxy
 * @createTime 2025/9/10
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MBOMAggRootImpl implements MBOMAggRoot {
    
    /** MBOM ID */
    private Long id;
    
    /** MBOM编码 */
    private String mbomCode;
    
    /** MBOM名称 */
    private String mbomName;
    
    /** 产品ID */
    private Long productId;
    
    /** 版本号 */
    private String version;
    
    /** 状态：DRAFT-草稿，REVIEWING-审核中，APPROVED-已审核，RELEASED-已发布，OBSOLETED-已作废 */
    private String status;
    
    /** 描述 */
    private String description;
    
    /** EBOM ID（如果从EBOM同步而来） */
    private Long ebomId;
    
    /** EBOM版本 */
    private String ebomVersion;
    
    /** 替代料集合 - key: substituteId, value: SubstituteMaterial */
    private final Map<Long, SubstituteMaterial> substituteMaterials = new ConcurrentHashMap<>();

    // === 事件集合 ===
    private final List<DomainEvent> domainEvents = new ArrayList<>();

    // === 事件相关方法 ===
    @Override
    public List<DomainEvent> getDomainEvents() {
        return Collections.unmodifiableList(domainEvents);
    }

    @Override
    public void addDomainEvent(DomainEvent event) {
        domainEvents.add(event);
    }

    @Override
    public void clearDomainEvents() {
        domainEvents.clear();
    }

    @Override
    public boolean hasDomainEvents() {
        return !domainEvents.isEmpty();
    }

    @Override
    public boolean hasNoDomainEvents() {
        return domainEvents.isEmpty();
    }

    @Override
    public MBOMSyncedFromEBOMEvent syncFromEBOM(Long ebomId, String ebomVersion, Long productId) {
        validateBusinessRule(this.id == null, "MBOM已存在，无法重复同步");
        
        this.ebomId = ebomId;
        this.ebomVersion = ebomVersion;
        this.productId = productId;
        this.status = "DRAFT";
        
        MBOMSyncedFromEBOMEvent event = new MBOMSyncedFromEBOMEvent(
                this.id, ebomId, ebomVersion, productId);
        
        addDomainEvent(event);
        return event;
    }

    @Override
    public MBOMCreatedEvent create(String mbomCode, String mbomName, Long productId, String version) {
        validateBusinessRule(this.id == null, "MBOM已存在，无法重复创建");
        validateBusinessRule(mbomCode != null && !mbomCode.trim().isEmpty(), "MBOM编码不能为空");
        validateBusinessRule(mbomName != null && !mbomName.trim().isEmpty(), "MBOM名称不能为空");
        validateBusinessRule(productId != null, "产品ID不能为空");
        validateBusinessRule(version != null && !version.trim().isEmpty(), "版本号不能为空");
        
        this.mbomCode = mbomCode;
        this.mbomName = mbomName;
        this.productId = productId;
        this.version = version;
        this.status = "DRAFT";
        
        MBOMCreatedEvent event = new MBOMCreatedEvent(
                this.id, mbomCode, productId, version);
        
        addDomainEvent(event);
        return event;
    }

    @Override
    public void update(String mbomName, String description) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("DRAFT".equals(this.status), "只有草稿状态的MBOM才能修改");
        validateBusinessRule(mbomName != null && !mbomName.trim().isEmpty(), "MBOM名称不能为空");
        
        this.mbomName = mbomName;
        this.description = description;
    }

    @Override
    public MBOMSubmittedForReviewEvent submitForReview(Long reviewerId, String submitComment) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("DRAFT".equals(this.status), "只有草稿状态的MBOM才能提交审核");
        validateBusinessRule(reviewerId != null, "审核人不能为空");
        
        this.status = "REVIEWING";
        
        MBOMSubmittedForReviewEvent event = new MBOMSubmittedForReviewEvent(
                this.id, reviewerId);
        
        addDomainEvent(event);
        return event;
    }

    @Override
    public MBOMApprovedEvent approve(String approveComment) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("REVIEWING".equals(this.status), "只有审核中的MBOM才能审核通过");
        
        this.status = "APPROVED";
        
        MBOMApprovedEvent event = new MBOMApprovedEvent(this.id);
        
        addDomainEvent(event);
        return event;
    }

    @Override
    public MBOMRejectedEvent reject(String rejectReason) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("REVIEWING".equals(this.status), "只有审核中的MBOM才能审核拒绝");
        validateBusinessRule(rejectReason != null && !rejectReason.trim().isEmpty(), "拒绝原因不能为空");
        
        this.status = "DRAFT"; // 拒绝后回到草稿状态
        
        MBOMRejectedEvent event = new MBOMRejectedEvent(this.id, rejectReason);
        
        addDomainEvent(event);
        return event;
    }

    @Override
    public MBOMReleasedEvent release() {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("APPROVED".equals(this.status), "只有已审核的MBOM才能发布");
        
        this.status = "RELEASED";
        
        MBOMReleasedEvent event = new MBOMReleasedEvent(
                this.id, this.version, this.productId);
        
        addDomainEvent(event);
        return event;
    }

    @Override
    public MBOMAssignedToWorkOrderEvent assignToWorkOrder(Long workOrderId) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("RELEASED".equals(this.status), "只有已发布的MBOM才能分配给工单");
        validateBusinessRule(workOrderId != null, "工单ID不能为空");
        
        MBOMAssignedToWorkOrderEvent event = new MBOMAssignedToWorkOrderEvent(
                this.id, workOrderId, this.version);
        
        addDomainEvent(event);
        return event;
    }

    @Override
    public MBOMObsoletedEvent obsolete(String obsoleteReason) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule(!"OBSOLETED".equals(this.status), "MBOM已经是作废状态");
        validateBusinessRule(obsoleteReason != null && !obsoleteReason.trim().isEmpty(), "作废原因不能为空");
        
        this.status = "OBSOLETED";
        
        MBOMObsoletedEvent event = new MBOMObsoletedEvent(
                this.id, this.version, this.productId);
        
        addDomainEvent(event);
        return event;
    }
    
    // ========== 替代料相关方法实现 ==========
    
    @Override
    public SubstituteMaterialAddedEvent addSubstituteMaterial(
            Long mbomItemId, Long substituteMaterialId, BigDecimal substituteRatio, 
            Integer priority, LocalDateTime validFrom, LocalDateTime validTo) {
        
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("DRAFT".equals(this.status), "只有草稿状态的MBOM才能添加替代料");
        validateBusinessRule(mbomItemId != null, "MBOM项ID不能为空");
        validateBusinessRule(substituteMaterialId != null, "替代料物料ID不能为空");
        validateBusinessRule(substituteRatio != null && substituteRatio.compareTo(BigDecimal.ZERO) > 0, 
                           "替代比例必须大于0");
        validateBusinessRule(priority != null && priority > 0, "优先级必须大于0");
        
        // 检查同一MBOM项下是否已存在相同的替代料
        boolean exists = substituteMaterials.values().stream()
                .anyMatch(sm -> sm.getMbomItemId().equals(mbomItemId) && 
                              sm.getSubstituteMaterialId().equals(substituteMaterialId));
        validateBusinessRule(!exists, "该MBOM项下已存在相同的替代料");
        
        // 生成替代料ID（这里简化处理，实际应该通过ID生成器）
        Long substituteId = System.currentTimeMillis();
        
        // 创建替代料实体
        SubstituteMaterial substituteMaterial = SubstituteMaterial.builder()
                .id(substituteId)
                .mbomItemId(mbomItemId)
                .substituteMaterialId(substituteMaterialId)
                .substituteRatio(substituteRatio)
                .priority(priority)
                .validFrom(validFrom)
                .validTo(validTo)
                .status("DRAFT")
                .build();
        
        // 添加到集合
        substituteMaterials.put(substituteId, substituteMaterial);
        
        // 创建事件
        SubstituteMaterialAddedEvent event = new SubstituteMaterialAddedEvent(
                this.id, mbomItemId, substituteMaterialId, substituteRatio, priority);
        
        addDomainEvent(event);
        return event;
    }
    
    @Override
    public SubstituteMaterialUpdatedEvent updateSubstituteMaterial(
            Long substituteId, BigDecimal substituteRatio, Integer priority,
            LocalDateTime validFrom, LocalDateTime validTo) {
        
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("DRAFT".equals(this.status), "只有草稿状态的MBOM才能修改替代料");
        validateBusinessRule(substituteId != null, "替代料ID不能为空");
        
        SubstituteMaterial substituteMaterial = substituteMaterials.get(substituteId);
        validateBusinessRule(substituteMaterial != null, "替代料不存在");
        
        // 更新替代料信息
        substituteMaterial.update(substituteRatio, priority, validFrom, validTo);
        
        // 创建事件
        SubstituteMaterialUpdatedEvent event = new SubstituteMaterialUpdatedEvent(
                this.id, substituteId, substituteRatio, priority);
        
        addDomainEvent(event);
        return event;
    }
    
    @Override
    public SubstituteMaterialRemovedEvent removeSubstituteMaterial(Long substituteId) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("DRAFT".equals(this.status), "只有草稿状态的MBOM才能移除替代料");
        validateBusinessRule(substituteId != null, "替代料ID不能为空");
        
        SubstituteMaterial substituteMaterial = substituteMaterials.get(substituteId);
        validateBusinessRule(substituteMaterial != null, "替代料不存在");
        
        Long mbomItemId = substituteMaterial.getMbomItemId();
        
        // 从集合中移除
        substituteMaterials.remove(substituteId);
        
        // 创建事件
        SubstituteMaterialRemovedEvent event = new SubstituteMaterialRemovedEvent(
                this.id, substituteId, mbomItemId);
        
        addDomainEvent(event);
        return event;
    }
    
    @Override
    public SubstituteMaterialApprovedEvent approveSubstituteMaterial(Long substituteId) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule(substituteId != null, "替代料ID不能为空");
        
        SubstituteMaterial substituteMaterial = substituteMaterials.get(substituteId);
        validateBusinessRule(substituteMaterial != null, "替代料不存在");
        
        // 审核通过
        substituteMaterial.approve();
        
        // 创建事件
        SubstituteMaterialApprovedEvent event = new SubstituteMaterialApprovedEvent(
                this.id, substituteId);
        
        addDomainEvent(event);
        return event;
    }
    
    @Override
    public SubstituteMaterialRejectedEvent rejectSubstituteMaterial(Long substituteId, String rejectReason) {
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule(substituteId != null, "替代料ID不能为空");
        
        SubstituteMaterial substituteMaterial = substituteMaterials.get(substituteId);
        validateBusinessRule(substituteMaterial != null, "替代料不存在");
        
        // 审核拒绝
        substituteMaterial.reject(rejectReason);
        
        // 创建事件
        SubstituteMaterialRejectedEvent event = new SubstituteMaterialRejectedEvent(
                this.id, substituteId, rejectReason);
        
        addDomainEvent(event);
        return event;
    }
    
    @Override
    public SubstituteMaterialAppliedToWorkOrderEvent applySubstituteMaterialToWorkOrder(
            Long substituteId, Long workOrderId, BigDecimal actualQuantity) {
        
        validateBusinessRule(this.id != null, "MBOM不存在");
        validateBusinessRule("RELEASED".equals(this.status), "只有已发布的MBOM才能应用替代料");
        validateBusinessRule(substituteId != null, "替代料ID不能为空");
        validateBusinessRule(workOrderId != null, "工单ID不能为空");
        validateBusinessRule(actualQuantity != null && actualQuantity.compareTo(BigDecimal.ZERO) > 0, 
                           "实际使用数量必须大于0");
        
        SubstituteMaterial substituteMaterial = substituteMaterials.get(substituteId);
        validateBusinessRule(substituteMaterial != null, "替代料不存在");
        validateBusinessRule(substituteMaterial.isAvailableForMES(), "替代料不可用于MES投料");
        
        // 创建事件
        SubstituteMaterialAppliedToWorkOrderEvent event = new SubstituteMaterialAppliedToWorkOrderEvent(
                this.id, substituteId, workOrderId, actualQuantity);
        
        addDomainEvent(event);
        return event;
    }
    
    /**
     * 获取替代料集合
     */
    public Map<Long, SubstituteMaterial> getSubstituteMaterials() {
        return Collections.unmodifiableMap(substituteMaterials);
    }
    
    /**
     * 验证业务规则
     */
    private void validateBusinessRule(boolean condition, String message) {
        if (!condition) {
            throw new IllegalStateException(message);
        }
    }


}